grammar VPL;

options{
	language=Python;
	output=AST;
}

/*-----------------------------------------------------
*LEXER RULES
*----------------------------------------------------*/

tokens {
	HEAD;
    PARAM;
    DECL;
    STATEMENTS;
    ASS;
    INT;
    FLT;

	MINIMUM =  'min';
	LEFT_PAREN =  '(';
	RIGHT_PAREN =  ')';
	PLUS =  '+';
	MINUS =  '-';
	MULTIPLY =  '*';
	DIVIDE =  '/';
	COMMA =  ',';
	SEMICOLON =  ';';
	VAR =  'var';
	FUNC =  'func';
	END_FUNC =  'end';
	ASSIGNMENT =  '=';
}
INTEGER: '0' | ('1'..'9' ('0'..'9')*);
FLOAT: (INTEGER '.' INTEGER+) | '.';
//NUMBER: INT | FLOAT;
IDENT: ('_'|'a'..'z'|'A'..'Z') ('_'|'a'..'z'|'A'..'Z'|'0'..'9')*;


WHITESPACE: (' ' | '\n' | '\r' | '\t' | '\u000C')+  { $channel = HIDDEN; } ;

/*-------------------------------------------------------
*PARSER RULES
*------------------------------------------------------*/


prog	:	(function)* -> ^(HEAD function*);

function:	FUNC^ IDENT params? declaration* statements END_FUNC;

declaration
	:	VAR list SEMICOLON -> ^(DECL list);

list	:	(IDENT COMMA!)* IDENT;

/*FIXME:: this is currently hacked to work with the assignment specification. the LAST statement should NOT be followed by a semicolon.*/
statements
	:	(statement (SEMICOLON statement?)*) -> ^(STATEMENTS statement*);
	

statement
	:	assign|(IDENT^ params);


params	:	 LEFT_PAREN list RIGHT_PAREN -> ^(PARAM list);


assign	:	 IDENT ASSIGNMENT^ expression;


expression
	:	term ( (PLUS | MINUS)^ term)* ;

term	:	factor ((MULTIPLY | DIVIDE)^ factor)* ;

factor	:	( number | IDENT | min_call | (LEFT_PAREN! expression RIGHT_PAREN!) ) ;

min_call:	MINIMUM^ LEFT_PAREN! expression COMMA! expression RIGHT_PAREN!;

number	:	int | float;

int	:	INTEGER -> ^(INT INTEGER);

float	:	FLOAT -> ^(FLT FLOAT);
